<template>
  <div class="crud-content" v-if="config">
    <div class="crud-search" v-if="config.search"><div :is="DynamicForm" :schema="config.search" :model="searchModel"></div></div>
    <div class="crud-actions" v-if="globalActions && globalActions.length > 0">
      <button v-for="(action, idx) in globalActions"
              :disabled="action.disabledState"
              :show="!action.hiddenState"
              :class="action.buttonClass" @click="globalActionHandler(action, $event)">
        {{action.label}}
      </button>
    </div>
    <div class="crud-data-list">
      <div ref="gridInstance" :is="DataGrid" :config="config.grid"
           @check-change="checkChangeHandler"
           @selected-change="selectedChangeHandler"></div>
    </div>
    <template v-for="modal in actionFormModals">
      <modal ref="operationInstance"
             :idx="modal.idx"
             :width="modal.modalWidth"
             :title="modal.formTitle"
             :disableEscClose="modal.disableEscClose"
             :staticModal="modal.staticModal"
             :showClose="modal.showClose">
        <div :is="DynamicForm" :schema="modal.formSchema" :model="modal.formModel"></div>
      </modal>
    </template>
  </div>
</template>

<script>
  import _ from 'lodash'
  import Vue from 'vue'
  import {api} from '../libs/ajax-service'
  import {localStorage} from '../libs/storage'
  import DataGrid from '../data-grid'
  import DynamicForm from '../dynamic-form'
  import Modal from '../modal/Modal.vue'
  import Confirm from '../modal/confirm-modal'
  import Toaster from '../toaster'

  export default {
    components: {Modal},
    props: {
      module: {
        required: true
      }
    },
    data () {
      return {
        DynamicForm,
        DataGrid,
        configContext: {},
        config: null,
        globalActions: [],
        globalActionHandler () {},
        actionFormModals: [],
        searchModel: {},

        key: null,
        cacheQuery: false,
        refreshGlobalActionStateDebounce: null
      }
    },
    created () {
      this.refreshGlobalActionStateDebounce = _.debounce(() => {
        _.forEach(this.globalActions, action => {
          Vue.set(action, 'disabledState', action.disabled ? action.disabled({}) : false)
          Vue.set(action, 'hiddenState', action.hidden ? action.hidden({}) : false)
        })
      }, 100, {leading: true})
      if (this.configContext && this.configContext.config && this.configContext.config.onCreated) {
        this.configContext.config.onCreated()
      }
    },
    computed: {
    },
    mounted () {
      this.initModule()
      if (this.configContext && this.configContext.config && this.configContext.config.onMounted) {
        this.configContext.config.onMounted()
      }
    },
    methods: {
      initModule () {
        let Context = this.module
        if (Context) {
          Vue.nextTick(() => {
            this.config = null
            Vue.nextTick(() => {
              this.configContext = new Context(this)
              this.key = this.configContext.key || null
              this.configContext.$context = this
              this.config = this.configContext.config
              this.transCrudConfig(this.config)
              // load search cache
              if (this.cacheQuery && this.key) {
                let query = localStorage.get(`${this.key}-data-grid-search`)
                if (query) {
                  let pagination = this.config.grid.pagination
                  if (pagination) {
                    if (query.pageSize !== undefined) {
                      pagination.pageSize = query.pageSize
                      delete query.pageSize
                    }
                    if (query.pageIndex !== undefined) {
                      pagination.pageIndex = query.pageIndex
                      delete query.pageIndex
                    }
                  }
                  this.searchModel = query
                }
              }
              Vue.nextTick(() => {
                this.$refs.gridInstance.reload()
              })
            })
          })
        }
      },
      transCrudConfig (config) {
        let $this = this
        let cacheQuery = false
        let key = $this.key

        let checkResultSuccess = function (data, action) {
          let rst = action.checkActionResultSuccess ? action.checkActionResultSuccess(data) : true
          rst && action.successMessage && Toaster.Toast(action.successMessage, Toaster.SUCCESS)
          !rst && action.errorMessage && Toaster.Toast(action.errorMessage, Toaster.SUCCESS)
          return rst
        }

        let deal = function (data, action) {
          let submitData = data
          // 判断是否需要提前处理数据（在弹窗前，即Form存在时展示前 或 Form不存在调用Api前），支持返回Promise
          if (action.actionDataPreDeal) {
            submitData = action.actionDataPreDeal(submitData)
          }
          // 如果有Form配置，则找出Form并显示
          if (action.formSchema) {
            _.forEach($this.actionFormModals, modal => {
              if (modal.idx === action.actionIdx) {
                modal.formSchema = {} // TODO 测试是否需要此步骤
                Vue.nextTick(() => {
                  modal.formSchema = _.cloneDeep(action.formSchema)
                })
                if (submitData.then instanceof Function) {
                  submitData.then(d => {
                    modal.formModel = d
                  })
                } else {
                  modal.formModel = submitData
                }
                return false
              }
            })
            _.find($this.$refs['operationInstance'], i => {
              return i.$attrs.idx === action.actionIdx
            }).open()
          } else {
            if (!action.apiUrl) {
              throw Error('全局按钮或行按钮需要配置以下其中一个值：customOperation/formSchema/apiUrl')
            }
            if (submitData.then instanceof Function) {
              submitData.then(d => {
                api(action.apiUrl, action.apiMethod, d).then(data => {
                  checkResultSuccess(data, action) && $this.$refs.gridInstance.reload()
                })
              })
            } else {
              api(action.apiUrl, action.apiMethod, submitData).then(data => {
                checkResultSuccess(data, action) && $this.$refs.gridInstance.reload()
              })
            }
          }
        }

        if (config.search) {
          cacheQuery = !!config.search.cache
          $this.cacheQuery = cacheQuery
          let search = {
            formClass: 'va-df-form-inline',
            ...config.search
          }
          $this.searchModel = (config.search.cache && $this.key && localStorage.get($this.key + '-data-grid-search')) ||
            config.search.defaultModel || {}
          if (!search.actions) {
            search.actions = [{
              type: 'submit',
              label: '查询',
              buttonClass: 'btn btn-primary'
            }]
          }
          if (!search.submitHandler) {
            search.submitHandler = function () {
              let gridInstance = $this.$refs.gridInstance
              if (gridInstance && gridInstance.reload) {
                let rst = gridInstance.reload()
                if (rst && rst.then instanceof Function) {
                  return rst
                } else {
                  return true
                }
              } else {
                return false
              }
            }
          }
          config.search = search
        }
        if (config.grid) {
          let grid = {...config.grid, key}
          if (config.grid.dataSourceUrl) {
            grid.dataSource = function (pageIndex, pageSize, sort) {
              let searchModel = _.cloneDeep($this.searchModel)
              if (config.search && config.search.formDataPreDeal) {
                searchModel = config.search.formDataPreDeal(searchModel)
              }
              let query = {...searchModel, pageIndex, pageSize}
              let rst = api(config.grid.dataSourceUrl, config.grid.httpMethod, query)
              if (cacheQuery && key) {
                localStorage.set(`${key}-data-grid-search`, {...$this.searchModel, pageIndex, pageSize})
              }
              if (config.grid.dataSourcePreDeal) {
                if (rst && rst.then) {
                  rst = rst.then(data => {
                    return config.grid.dataSourcePreDeal(data)
                  })
                } else {
                  return config.grid.dataSourcePreDeal(rst)
                }
              }
              return rst
            }
          }
          if (!config.grid.actions) {
            config.grid.actions = []
          }
          if (!config.globalActions) {
            config.globalActions = []
          } else {
            // 设置action中的__global属性，表示是全局按钮
            for (let globalAction of config.globalActions) {
              globalAction.__global = true
            }
          }
          let context = {}
          let actionFormModals = []
          // 按钮配置合并，全局按钮在后
          let actions = [...config.grid.actions, ...config.globalActions]
          _.forEach(actions, (action, idx) => {
            action.actionIdx = idx
            if (!action.__global) {
              context.disabled = function (action) {
                return action.disabled ? action.disabled(this.getNode().data) : false
              }
              context.show = function (action) {
                return action.hidden ? !action.hidden(this.getNode().data) : true
              }
            }
            if (action.formSchema) {
              if (!action.formSchema.actions) {
                if (!action.apiUrl && !action.formSchema.submitHandler) {
                  action.formSchema.actions = [
                    {
                      type: 'button',
                      label: '关闭',
                      buttonClass: 'btn btn-light',
                      handler () {
                        let idx = _.findIndex(actions, act => {
                          return action.actionIdx === act.actionIdx
                        })
                        _.find($this.$refs['operationInstance'], i => {
                          return i.$attrs.idx === idx
                        }).close()
                        return true
                      }
                    }
                  ]
                } else {
                  action.formSchema.actions = [
                    {
                      type: 'button',
                      label: '取消',
                      buttonClass: 'btn btn-light',
                      handler () {
                        let idx = _.findIndex(actions, act => {
                          return action.actionIdx === act.actionIdx
                        })
                        _.find($this.$refs['operationInstance'], i => {
                          return i.$attrs.idx === idx
                        }).close()
                        return true
                      }
                    },
                    {
                      type: 'submit',
                      label: '提交',
                      buttonClass: 'btn btn-primary'
                    }
                  ]
                }
              }
              let originalSubmitHandler = action.formSchema.submitHandler
              action.formSchema.submitHandler = function (formModel) {
                formModel = _.cloneDeep(formModel)
                if (action.formDataPreDeal) {
                  formModel = action.formDataPreDeal(formModel)
                }
                // 如果formModel === false，则取消提交行为
                if (formModel === false) {
                  return false
                }
                if (action.apiUrl) {
                  return api(action.apiUrl, action.apiMethod, formModel).then(data => {
                    let rst = checkResultSuccess(data, action)
                    if (rst && action.autoCloseModal) {
                      let idx = _.findIndex(actions, act => {
                        return action.actionIdx === act.actionIdx
                      })
                      _.find($this.$refs['operationInstance'], i => {
                        return i.$attrs.idx === idx
                      }).close()
                    }
                    return data
                  })['finally'](() => {
                    $this.$refs.gridInstance.reload()
                  })
                } else if (originalSubmitHandler) {
                  let closeModalFunc = () => {
                    let idx = _.findIndex(actions, act => {
                      return action.actionIdx === act.actionIdx
                    })
                    _.find($this.$refs['operationInstance'], i => { return i.$attrs.idx === idx }).close()
                  }
                  let refreshGridFunc = () => {
                    $this.$refs.gridInstance.reload()
                  }
                  return originalSubmitHandler(formModel, closeModalFunc, refreshGridFunc)
                }
              }
              actionFormModals.push({
                idx,
                formTitle: action.formTitle,
                formSchema: {},
                formModel: {},
                modalWidth: action.modalWidth,
                disableEscClose: action.disableEscClose === undefined ? false : !!action.disableEscClose,
                staticModal: action.staticModal === undefined ? true : !!action.staticModal,
                showClose: action.showClose === undefined ? true : !!action.showClose
              })
            }
            context.operation = function (action, evt) {
              evt.preventDefault()
              evt.stopPropagation()
              // 获取当前按钮所在行的数据，全局的为{}
              let data = action.__global ? {} : this.getNode().data
              // 如果按钮配置中有自处理函数，则直接调用
              let dealFunc = action.customOperation || deal
              data = _.cloneDeep(data)
              if (action.preConfirm) {
                Confirm(action.preConfirm.title, action.preConfirm.message, null, null, action.modalWidth, action.disableEscClose, action.staticModal, action.showClose).then(rst => {
                  if (rst) {
                    dealFunc(data, action)
                  }
                })
              } else {
                dealFunc(data, action)
              }
            }
          })
          $this.actionFormModals = actionFormModals

          if (config.grid.actions.length > 0) {
            let actionColumn = {
              field: '_operation',
              title: '操作',
              width: config.grid.actionColumnWidth || 80,
              fixed: 'right',
              disableHidden: true
            }
            actionColumn.cellTemplate = '<div class="crud-operation-list">\n  <button v-for="action in actions"\n          :class="action.buttonClass"\n          :disabled="disabled(action)"\n          v-show="show(action)"\n          @click="operation(action, $event)">\n    {{action.label}}\n  </button>\n</div>'
            actionColumn.context = {...context, actions: [...config.grid.actions]}
            grid.columns.push(actionColumn)
          }
          $this.globalActions = config.globalActions
          $this.globalActionHandler = context.operation
          config.grid = grid
        }
        $this.refreshGlobalActionStateDebounce && $this.refreshGlobalActionStateDebounce()
      },
      checkChangeHandler (data) {
        this.configContext.checked = data
        this.refreshGlobalActionStateDebounce && this.refreshGlobalActionStateDebounce()
      },
      selectedChangeHandler (data) {
        this.configContext.selected = data
        this.refreshGlobalActionStateDebounce && this.refreshGlobalActionStateDebounce()
      }
    },
    beforeDestroy () {
      if (this.configContext && this.configContext.config && this.configContext.config.onDestroy) {
        this.configContext.config.onDestroy()
      }
    },
    watch: {
      '$route' () {
        this.configContext && this.configContext.onRouteChange && this.configContext.onRouteChange()
      }
    }
  }
</script>
